/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2008，所有权利保留。
 * 
 * 文件名：	ExternalRequestHandler.java
 * 模块说明：	
 * 修改历史：
 * Jan 9, 2008 - zhangyanbo - 创建。
 */
package com.hd123.rumba.request;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.rmi.Naming;
import java.util.List;
import java.util.StringTokenizer;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Session;
import net.sf.hibernate.Transaction;

import org.apache.log4j.Logger;

import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.domain.IDomainMgr;
import com.hd123.rumba.extern.IExternalQt;
import com.hd123.rumba.extern.ISecurity;
import com.hd123.rumba.extern.PermissionInfo;
import com.hd123.rumba.extern.SessionInfo;
import com.hd123.rumba.qt.QueryResultSession;
import com.hd123.rumba.qt.QuerySourceSession;
import com.hd123.rumba.runtime.HibernateSession;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.user.IPermission;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.user.IUserMgr;
import com.hd123.rumba.util.StringUtil;

/**
 * @author zhangyanbo
 * 
 */
public class ExternalRequestHandler extends HttpServlet {

  public static String SECURITY = "";
  public static String EXTERNALQT = "";

  protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    processRequest(request, response);
  }

  protected void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    request.setCharacterEncoding(StringUtil.ENCODING_CHARSET);
    response.setCharacterEncoding(StringUtil.ENCODING_CHARSET);

    Logger logger = Logger.getLogger("com.hd123.rumba.TIME");
    String qs = StringUtil.decodePathInfo(request.getQueryString());
    logger.debug(request.getRemoteHost() + ": " + request.getRequestURI() + "?" + qs + " !@# "
        + request.getSession().getId());
    HttpSession session = request.getSession();
    String url = null;
    Dictionary dd = null;
    ExternalSession.setSession(session);
    try {
      dd = new Dictionary(request, response);
      request.setAttribute("dd", dd);
      injectSessionInfo(request);

      String actionName = request.getPathInfo().replace('/', '.');
      Action action = (Action) findAuthroizedAction(actionName);
      if (action != null) {
        action.init(dd);
        url = action.execute();
      } else {
        dd.setWorkingTemplate(ActionConstants.NOTIMPLEMENTED);
        url = ActionConstants.APPLICATIONFRAME;
      }
      if (!url.equals(ActionConstants.DIRECT)) {
        url = JspLib.getTemplate(url);
        RequestDispatcher rd = request.getSession().getServletContext().getRequestDispatcher(url);
        rd.forward(request, response);
      }
    } catch (Throwable ex) {
      Throwable e = ex;
      if (e instanceof InvocationTargetException) {
        e = ((InvocationTargetException) e).getTargetException();
      }
      dd.put("exception", e);
      url = JspLib.getTemplate("application/GeneralError.jsp");
      RequestDispatcher rd = request.getSession().getServletContext().getRequestDispatcher(url);
      rd.forward(request, response);
    } finally {
      ExternalSession.removeSession();
      try {
        HibernateSession.closeSession();
        if (dd != null && !dd.containsKey("KeepQuerySourceAndResultSessions")) {
          QuerySourceSession.closeSession();
          QueryResultSession.closeSession();
        }
      } catch (HibernateException e) {
        logger.error(e);
      }
    }
  }

  // Session信息注入
  public void injectSessionInfo(HttpServletRequest request) throws Exception {
    IDomain domain = ExternalSession.getCurrentDomain();
    IUser user = ExternalSession.getCurrentUser();
    if (domain != null && user != null)
      return;

    ISecurity security = (ISecurity) Naming.lookup(SECURITY);
    SessionInfo si = security.getSessionInfo(request.getParameter("xid"));
    if (si == null)
      throw new Exception("无法访问系统。");

    String currentDomainUuid = si.getCurrentDomainUuid();
    if (currentDomainUuid == null)
      throw new Exception("未提供登录域信息。");

    IUserMgr userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    OperateContext operCtx = new OperateContext(userMgr.getSysUser());
    Session sess = HibernateSession.getSession();
    Transaction tx = sess.beginTransaction();
    try {
      domain = injectDomain(si, operCtx);
      user = injectUser(si, domain, operCtx);
      HibernateSession.commit(tx);
    } catch (Exception e) {
      HibernateSession.rollback(tx);
      throw e;
    } finally {
      sess.flush();
    }

    ExternalSession.setCurrentDomain(domain);
    // 权限注入
    user.addToPermissionMap(si.getPermissions());
    ExternalSession.setCurrentUser(user);
  }

  // 域注入
  private IDomain injectDomain(SessionInfo si, OperateContext operCtx) throws Exception {
    IDomainMgr domainMgr = (IDomainMgr) NamingMgr.getInstance().lookupMgr(IDomainMgr.class);
    IDomain domain = domainMgr.getDomain(si.getCurrentDomainUuid());
    if (domain != null)
      return domain;
    String domainCode = null;
    List list = HibernateSession.getSession().find(
        "select max(o.code) from " + IDomain.class.getName() + " o where o.code like ?", "0%",
        Hibernate.STRING);
    if (list.size() > 0) {
      domainCode = (String) list.get(0);
      if (domainCode != null)
        domainCode = StringUtil.increaseString(domainCode);
      else
        domainCode = "0001";
    } else
      domainCode = "0001";
    domain = domainMgr.createDomain(domainMgr.getRootDomain(), domainCode, domainCode);
    domain.setUuid(si.getCurrentDomainUuid());
    domainMgr.saveDomainWithUuid(domain, operCtx);
    return domain;
  }

  // 用户注入
  private IUser injectUser(SessionInfo si, IDomain domain, OperateContext operCtx) throws Exception {
    IUserMgr userMgr = (IUserMgr) NamingMgr.getInstance().lookupMgr(IUserMgr.class);
    IUser user = userMgr.getUser(si.getCurrentUserUuid());
    if (user != null)
      return user;
    if (userMgr.getUserByLogin(domain, si.getCurrentUserCode()) != null)
      throw new Exception("已经存在代码为 " + si.getCurrentUserCode() + " 的用户。");
    user = userMgr.createUser(domain);
    user.setLogin(si.getCurrentUserCode());
    user.setName(si.getCurrentUserName());
    user.setUuid(si.getCurrentUserUuid());
    userMgr.saveUserWithUuid(user, operCtx);
    return user;
  }

  public static void saveQueryDef(HttpSession session, String queryDefUuid, IPermission permission,
      String operatorUuid) throws Exception {
    if (!ExternalSession.isExternalSession(session))
      return;
    IExternalQt eqt = (IExternalQt) Naming.lookup(EXTERNALQT);
    PermissionInfo pi = new PermissionInfo(permission.getCode(), permission.getName());
    eqt.saveQueryDef(queryDefUuid, pi, operatorUuid);
  }

  public static void removeQueryDef(HttpSession session, String queryDefUuid, String operatorUuid)
      throws Exception {
    if (!ExternalSession.isExternalSession(session))
      return;
    IExternalQt eqt = (IExternalQt) Naming.lookup(EXTERNALQT);
    eqt.removeQueryDef(queryDefUuid, operatorUuid);
  }

  // 寻找授权访问的Action，如果找不到，则返回null
  private Action findAuthroizedAction(String actionName) throws Exception {
    // 只授权访问\qt\下的内容
    if (!actionName.startsWith(".qt."))
      return null;
    StringTokenizer pacs = new StringTokenizer(ActionConstants.ACTIONPACKAGE, ";");
    Class clazz = null;
    while (pacs.hasMoreTokens()) {
      try {
        clazz = Class.forName(pacs.nextToken() + actionName);
        break;
      } catch (ClassNotFoundException e) {
      }
    }
    if (clazz == null)
      return null;
    Action action = (Action) clazz.newInstance();
    return action;
  }
}
